#ifndef _EPOLLSERVER_HPP_
#define _EPOLLSERVER_HPP_

#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "Sock.hpp"
#include "log.hpp"
#include "Epoll.hpp"

using std::cout;
using std::endl;
using std::string;

static const int default_port = 8080;
static const int gnum = 64;

class EpollServer
{
    using func_t = std::function<void (string)>;
public:
    EpollServer(func_t HandlerRequest, const int port = default_port)
        :_HandlerRequest(HandlerRequest)
        ,_port(port)
        ,_revs_num(gnum)
    {
        // 0.申请对应的空间
        _revs = new epoll_event[_revs_num];
        // 1.创建套接字的三个接口
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        // 2.创建epoll模型
        _epfd = Epoll::CreateEpoll();
        logMessage(NORMAL, "init success, listensock: %d, epfd: %d", _listensock, _epfd);
        // 3.把listensock放入epoll模型
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLL_CTL_ADD)) exit(6);  // 把_listensock 放入epoll中，失败了就退出
        logMessage(NORMAL, "add listensock to epoll success");
    }

    void start()
    {
        int timeout = 1000;  // 这是一个时间,让其非阻塞等待,如果让timeout = -1则为阻塞式等待
        while (true)
        {
           int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);  // 接受epoll的等待的结果
           switch(n)
           {
            case 0:
                logMessage(NORMAL, "time out ...");
                break;
            case -1:
                logMessage(ERROR, "epoll wait error: %d: %s", errno, strerror(errno));
                break;
            default:
                // 等待成功
                logMessage(NORMAL, "get a new link.");
                HandlerEvent(n);
                break;
           }
        }
    }

    void HandlerEvent(int n)
    {
        assert(n > 0);
        for (int i = 0; i < n; i++)
        {
            uint32_t revents = _revs[i].events;
            int sock = _revs[i].data.fd;

            // 读事件就绪
            if (revents & EPOLLIN)
            {
                if (sock == _listensock) Accepter();
                else    Recver(sock);
            }
            if (revents & EPOLLOUT)
            {
                // 写事件就绪 TODO
            }
        }
    }

    void Accepter()
    {
        string client_ip;
        uint16_t client_port;
        int sock = Sock::Accpet(_listensock, &client_port, & client_ip);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error!");
            return ;
        }
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN))   return ;
        logMessage(NORMAL, "add new sock: %d to epoll success", sock);
    }

    void Recver(int sock)
    {
        // 1.读取数据
        char buffer[10240];
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            buffer[s] = 0;
            _HandlerRequest(buffer);  // 处理数据
        }
        else if (s == 0)
        {
            // 对方关闭了
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;

            logMessage(NORMAL, "client[%d] quit, me too!", sock);
            close(sock);
        }
        else
        {
            // 读取失败
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;

            logMessage(ERROR, "client[%d] recv error, close error sock ...", sock);
            close(sock);
        }
    }

    ~EpollServer()
    {
        if (_listensock >= 0) close(_listensock);
        if (_epfd >= 0) close(_epfd);
        if (_revs)  delete []_revs;
    }
private:
    int _listensock;
    uint16_t _port;
    int _epfd;   // 创建epoll模型的返回值
    struct epoll_event* _revs;  // epoll模型的事件类型
    int _revs_num;  // epoll模型的个数
    func_t _HandlerRequest;  // 读取到数据后进行处理数据的方法
};

#endif